/* Generated by Interface Builder */

#import "ClassManager.h"
#import "MenuManager.h"
#import <appkit/Application.h>
#import <appkit/Text.h>
#import <appkit/Panel.h>
#import <appkit/NXBrowser.h>
#import <objc/objc-load.h>
#import <objc/Storage.h>
#import <libc.h>
#import <strings.h>


id loadList ; // this global var points to a "Storage" list of
                // 2-element malloced arrays of chars, where element
		// 0 contains the classname and element 1 contains
		// the pathname of every loaded class

struct loadClass
{ char *className ;
  char *dotOFileName ;
} ;

@implementation ClassManager: WindowManager

+ initialize ;
// initialize the loadList
{ loadList = [[Storage new] initCount:0
                 elementSize: sizeof(struct loadClass)
                 description:"{**}"] ;
  return [super initialize] ;
}

+(int) loadIndex: (char *) nameOfClass ;
// if nameOfClass is in the load list, return its index,
// else return -1
{ int i, knt ;
  struct loadClass *lc ;
  knt = [loadList count] ;
  for(i = 0 ; i < knt ; i++)
  { lc = (struct loadClass *) [loadList elementAt: i] ;
    if(!strcmp(lc->className, nameOfClass))
      return i ;
  }
  return -1 ;
}

+ loadList ;
{ return loadList ;
}

+ unload: (const char *) aClass;
// unload the class with name aClass
{ char *moduleNames[2], *textBuf ;
  int i, loadNumber, loadKnt, textLen, maxLen ;
  struct loadClass *lcPtr ;    
  NXStream *aStream ;

  aStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
  loadKnt = [loadList count] ;
  moduleNames[1] = NULL ;
  loadNumber = [ClassManager loadIndex: (char *) aClass] ;
  if(loadNumber != -1) // module is loaded...
  { for(i = loadKnt ; i > loadNumber ; i--)
      objc_unloadModules(aStream, NULL) ; // unload all classes
    lcPtr = [loadList elementAt: i] ;
    free(lcPtr->className) ;
    free(lcPtr->dotOFileName) ;
    [loadList removeAt: i] ; // remove this class from loadList
    loadKnt-- ;
    for( ; i < loadKnt ; i++) // reload unloaded classes
    { lcPtr = (struct loadClass *) [loadList elementAt: i] ;
      moduleNames[0] = lcPtr->dotOFileName ;
      objc_loadModules(moduleNames, aStream, NULL, NULL, NULL) ;
    }
  }
  NXGetMemoryBuffer(aStream, &textBuf, &textLen, &maxLen);
  [NXApp printf: textBuf];
  NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
  [[NXApp loadedClassesBrowser] loadColumnZero] ;
  return self ;
}

+ unloadAll ;
// unload all incrementally loaded classes
{ char *textBuf ;
  NXStream *aStream ;
  int i, loadKnt, textLen, maxLen ;
  struct loadClass *lcPtr ;    
  loadKnt = [loadList count] ;
  aStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
  for(i = 0 ; i < loadKnt ; i++)
  { objc_unloadModules(aStream, NULL) ;
    lcPtr = [loadList elementAt: 0] ;
    free(lcPtr->className) ;
    free(lcPtr->dotOFileName) ;
    [loadList removeAt: 0] ;
  }
  NXGetMemoryBuffer(aStream, &textBuf, &textLen, &maxLen);
  [NXApp printf: textBuf];
  NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
  [[NXApp loadedClassesBrowser] loadColumnZero] ;
  [[NXApp loadedClassesBrowser] loadColumnZero] ;
  return self ;  
}


- className: (char *) name ;
{ // copy className into ivar
  strncpy(className, name, 63) ;
  return self ;
}
 

- classText: (char *) theText ;
{ // copy theText into text object
  [textView setText: theText] ;
  [self setDocEdited:YES];
  return self ;
}
 
- compile:sender
{ char buf[512] ;
  char tmpFile[20] = "CBXXXXXX" ;
  if([self isDocEdited]) // be sure file is saved first
    [self save: self] ;
  // use awk to create .h file.  We should probably refine
  // this script.  it can't deal with @implementation a:b, there
  // must be a blank after the colon, thus a: b
  mktemp(tmpFile) ;
  [self message: "Creating .h file..."] ;
  sprintf(buf,
"awk '\\\n\
/#pragma .h/      { $1 = \"\";$2=\"\"; print}\\\n\
/@implementation/ { $1 = \"@interface\"; print ;state++ }\\\n\
/^{/               { if(state == 1) state++ }\\\n\
                  { if(state == 2) print }\\\n\
/^}/               { if(state == 2) state++ }\\\n\
/^[+-]/           { if(state == 3) print }\\\n\
END               { print \"@end\"}'\\\n\
< %s.m > %s.h",className, className, className ) ;
  system(buf) ;
  // compile into .o file
  sprintf(buf, "cc -c -I /usr/include/objc -Wall -o %s.o %s.m"
     "  2> /tmp/%s", className, className, tmpFile) ;
  [self message: "Compiling..."] ;
  if(system(buf)) // non-zero exit status == errors
  { sprintf(buf,"/tmp/%s",tmpFile) ;
    [NXApp appendFileToTranscript: buf] ;
    NXRunAlertPanel("CB","Compilation errors: see Transcript Window\n",
         NULL,NULL,NULL) ;
    sprintf(buf,"rm /tmp/%s.m /tmp/%s.o /tmp/%s 2> /dev/null",
         tmpFile,tmpFile,tmpFile) ;
    system(buf) ;
  } 
  [self message: ""] ;
  return self ;
}

- (char *) extension ;
{ // provide file extension
  return "m" ;
}


- load:sender ;
{ char *moduleNames[2] ;
  struct loadClass lc ;
    
  NXStream *aStream ;
  aStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
  moduleNames[1] = NULL ;
  
  // if class is already loaded, we'll have to unload
  // all classes loaded after it, then reload all unloaded
  // classes except it.
  [self message: "Loading..."] ;
  [ClassManager unload: className] ;
  // load current module. Note that we have moved the module
  // to the end of the loadlist, so subsequent reloads of
  // it are quicker.
  lc.className = malloc(strlen(className) + 1) ;
  strcpy(lc.className,className) ;
  lc.dotOFileName = malloc(strlen(fileName) + 1) ;
  strcpy(lc.dotOFileName,fileName) ;
  lc.dotOFileName[strlen(lc.dotOFileName) -1] = 'o' ;
  moduleNames[0] = lc.dotOFileName ;
  objc_loadModules(moduleNames, aStream, NULL, NULL, NULL) ;
  [loadList addElement: (void *) &lc] ;
  NXSeek(aStream, 0L, NX_FROMSTART) ;
  NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
  [[NXApp loadedClassesBrowser] loadColumnZero] ;
  [self message: ""] ;
  return self ;
}


@end
